#include <config.h>
#include <render.h>
#include <stdlib.h>
#include <file.h>
#include <string.h>
#include <unistd.h>

static pthread_t g_tAutoPlayThreadID;
static pthread_mutex_t g_tAutoPlayThreadMutex = PTHREAD_MUTEX_INITIALIZER;
static int g_bAutoPlayThreadShouldExit = 0;
static T_PageCfg g_tPageCfg;

static int g_iStartNumberToRecord = 0;
static int g_iCurFileNumber = 0;
static int g_iFileCountHaveGet = 0; // 当前目录下已经记录的文件数
static int g_iFileCountTotal = 0;

// 文件索引是一个用于标识文件在某个列表或集合中位置的数值。它通常是一个整数，可以作为文件在文件列表或数组中的位置或顺序的唯一标识符。
// 检查g_iNextProcessFileIndex 是否小于 g_iFileCountHaveGet，可以确定是否还有未处理的文件。
// 通过使用文件索引，我们可以在文件列表或集合中追踪文件的顺序，并按照需要访问和处理文件。
static int g_iNextProcessFileIndex = 0;

#define FILE_COUNT 10
static char g_apstrFileNames[FILE_COUNT][256];

//  * 功能描述： 每次使用"连播"功能时,都调用此函数,它使得从第1个文件开始"连播"
static void ResetAutoPlayFile(void)
{
    g_iStartNumberToRecord = 0;
    g_iCurFileNumber = 0;
    g_iFileCountHaveGet = 0;
    g_iFileCountTotal = 0;
    g_iNextProcessFileIndex = 0;
}

//  * 功能描述： 获得下一个要播放的图片的名字
//  * 输入参数： 无
//  * 输出参数： strFileName - 里面存有下一个要播放的图片的名字(含绝对路径)
//  * 返 回 值： 0 - 成功, 其他值 - 失败
static int GetNextAutoPlayFile(char *strFileName)
{
    int iError;
    if (g_iNextProcessFileIndex < g_iFileCountHaveGet)
    {
        // 说明还有未处理的函数，拷贝到strfilename里
        strncpy(strFileName, g_apstrFileNames[g_iNextProcessFileIndex], 256);
        g_iNextProcessFileIndex++;
        return 0;
    }
    else
    {
        // 表示当前目录拷贝完了，置为0然后读下一层
        g_iCurFileNumber = 0;
        g_iFileCountHaveGet = 0;
        g_iFileCountTotal = FILE_COUNT;
        g_iNextProcessFileIndex = 0;
        iError = GetFilesIndir(g_tPageCfg.strSelectedDir, &g_iStartNumberToRecord, &g_iCurFileNumber, &g_iFileCountHaveGet, g_iFileCountTotal, g_apstrFileNames);
        if (iError || g_iNextProcessFileIndex >= g_iFileCountHaveGet)
        {
            // 文件读取失败，再次从头读起(连播模式下循环显示)
            g_iStartNumberToRecord = 0;
            g_iCurFileNumber = 0;
            g_iFileCountHaveGet = 0;
            g_iFileCountTotal = FILE_COUNT;
            g_iNextProcessFileIndex = 0;

            iError = GetFilesIndir(g_tPageCfg.strSelectedDir, &g_iStartNumberToRecord, &g_iCurFileNumber, &g_iFileCountHaveGet, g_iFileCountTotal, g_apstrFileNames);
        }

        if (iError == 0)
        {
            if (g_iNextProcessFileIndex < g_iFileCountHaveGet)
            {
                strncpy(strFileName, g_apstrFileNames[g_iNextProcessFileIndex], 256);
                g_iNextProcessFileIndex++;
                return 0;
            }
        }
    }
    return -1;
}


//  * 功能描述： 准备显示下一图片: 取出下图片的数据,存入VideoMem中
//  * 输入参数： bCur : 0 - 表示这是做准备用的, 有可能无法获得videomem
//  *                   1 - 表示必须获得videomem, 因为这是马上就要在LCD上显示出来的
//  * 输出参数： 无
//  * 返 回 值： NULL   - 无法获得VideoMem,所以下一个图片没有
static PT_VideoMem PrepareNextPicture(int bCur)
{
    T_PixelDatas tOriginIconPixelDatas;
    T_PixelDatas tPicPixelDatas;
    PT_VideoMem ptVideoMem;
    int iError;
    int iXres, iYres, iBpp;
    int iTopLeftX, iTopLeftY;
    float k;
    char strFileName[256];

    //拿到显示设备的数据
    GetDispResolution(&iXres, &iYres, &iBpp);
    ptVideoMem = GetVideoMem(-1, bCur);
    if(ptVideoMem == NULL)
    {
        DBG_PRINTF("cat not get video mem for browse page!\n");
        return NULL;
    }

    ClearVideoMem(ptVideoMem, COLOR_BACKGOUND);

    while(1)
    {
        //获得下一个要连播图片的名字
        iError = GetNextAutoPlayFile(strFileName);
        if(iError)
        {
            DBG_PRINTF("GetNextAutoPlayFile error!\n");
            PutVideoMum(ptVideoMem);
            return NULL;
        }

        //获得像素数据
        iError = GetPixelDatasFrmFile(strFileName, &tOriginIconPixelDatas);

        if(0 == iError)
            break;
    }

    //把图片等比例缩放到Videomem,居中显示，先算出缩放后的大小
    k = (float)tOriginIconPixelDatas.iHeight / tOriginIconPixelDatas.iWidth;
    tPicPixelDatas.iWidth = iXres;
    tPicPixelDatas.iHeight = iXres * k;
    if(tPicPixelDatas.iHeight > iYres)
    {
        tPicPixelDatas.iWidth = iYres / k;
        tPicPixelDatas.iHeight = iYres;
    }
    tPicPixelDatas.iBpp = iBpp;
    tPicPixelDatas.iLineBytes = tPicPixelDatas.iWidth * tPicPixelDatas.iBpp / 8;
    tPicPixelDatas.iTotalBytes = tPicPixelDatas.iLineBytes * tPicPixelDatas.iHeight;
    tPicPixelDatas.aucPixelDatas = malloc(tPicPixelDatas.iTotalBytes);
    if(tPicPixelDatas.aucPixelDatas == NULL)
    {
        PutVideoMem(ptVideoMem);
        return NULL;
    }

   //2.缩放
   PicZoom(&tOriginIconPixelDatas, &tPicPixelDatas);

   //3.计算居中显示时左上角的坐标
   iTopLeftX = (iXres - tPicPixelDatas.iWidth) / 2;
   iTopLeftY = (iYres - tPicPixelDatas.iHeight) / 2;

   //4.合并进VideoMem
   PicMerge(iTopLeftX, iTopLeftY, &tPicPixelDatas, &ptVideoMem->tPixelDatas);

   //5.释放原始数据和缩放后的数据
   FreePixelDatasFrmFile(&tOriginIconPixelDatas);
   free(tPicPixelDatas.aucPixelDatas);
   return ptVideoMem; 
}

//  * 功能描述： "连播页面"的子线程函数:用于显示  (主线程用于读取输入数据)
//  * 输入参数： pVoid - 未用
//  * 输出参数： 无
//  * 返 回 值： NULL   - 正常退出
static void *AutoPlayThreadFunction(void *pVoid)
{
    int bFirst = 1;
    int bExit;
    PT_VideoMem ptVideoMem;

    ResetAutoPlayFile();

    while(1)
    {
        //判读是否要退出
        pthread_mutex_lock(&g_tAutoPlayThreadMutex);
        bExit = g_bAutoPlayThreadShouldExit;
        pthread_mutex_unlock(&g_tAutoPlayThreadMutex);

        if(bExit)
            return NULL;
        
        //准备即将显示的图片
        ptVideoMem = PrepareNextPicture(0);

        //根据时间显示
        if(!bFirst)
        {
            sleep(g_tPageCfg.iIntervalSecond);
        }
        bFirst = 0;

        if(ptVideoMem == NULL)
        {
            ptVideoMem = PrepareNextPicture(1);
        }

        //刷新到设备
        FlushVideoMemToDev(ptVideoMem);
        PutVideoMum(ptVideoMem);
    }

    return NULL;
}

//  * 功能描述： "连播页面"的主线程函数: 用于读取输入数据
//  * 输入参数： ptParentPageParams - 内含上一个页面(父页面)的参数
static void AutoPageRun(PT_PageParams ptParentPageParams)
{
    T_InputEvent tInputEvent;
    int iRet;
    char *pcTmp;

    //获得配置值: 显示哪一个目录下的文件, 显示图片的间隔 
    GetPageCfg(&g_tPageCfg);

    //路径不为空就处理目录路径字符
    if(ptParentPageParams->strCurPictureFile[0] != '\0')
    {
        strcpy(g_tPageCfg.strSelectedDir, ptParentPageParams->strCurPictureFile);
        //查找最后一个'/'，也就是找到最后一个目录分隔符
        pcTmp = strrchar(g_tPageCfg.strSelectedDir, '/');
        if(pcTmp != g_tPageCfg.strSelectedDir)
        {
            *pcTmp = '\0'
        }
    }

    pthread_create(&g_tAutoPlayThreadID, NULL, AutoPlayThreadFunction, NULL);
    //当前线程等待触摸屏输入，点击了触摸屏，就让线程退出（暂时先这样）
    while(1)
    {
        iRet = GetInputEvent(&tInputEvent);
        if(0 == iRet)
        {
            pthread_mutex_lock(&g_tAutoPlayThreadMutex);
            g_bAutoPlayThreadShouldExit = 1;    //退出的标志
            pthread_mutex_unlock(&g_tAutoPlayThreadMutex);
            pthread_join(g_tAutoPlayThreadID, NULL);
            return;
        }
    }

}
static T_PageAction g_tAutoPageAction = {
    .name = "auto",
    .Run = AutoPageRun,
};
//  * 功能描述： 注册"连播页面"
//  * 输入参数： 无
//  * 输出参数： 无
//  * 返 回 值： 0 - 成功, 其他值 - 失败
int AutoPageInit(void)
{
    return RegisterPageAction(&g_tAutoPageAction);
}